import React, { StrictMode, useRef } from 'react'

const boxStyle = {
  margin: '10px',
  border: '1px solid #ccc',
  borderRadius: '10px',
  padding: '10px',
}

// ref 会在 componentDidMount 或 componentDidUpdate 生命周期钩子触发前更新。
// getSnapshotBeforeUpdate() 后面更新dom和ref
// 不要直接在render中使用ref不是最新的可能为null
export class RefTemplate extends React.Component {
  constructor(props) {
    super(props)
    this.state = { isToggleOn: true }
    this.classSonRef = React.createRef()
    this.funSonRef = React.createRef()
  }
  componentDidMount() {
    this.classSonRef.current.focusTextInput()
    console.log('funSonRef...', this.funSonRef)
  }
  render() {
    return (
      <div style={boxStyle}>
        <p>这是父组件</p>
        <RefSon ref={this.classSonRef}></RefSon>
        {/* 你不能在函数组件上使用 ref 属性，因为它们没有实例： */}
        <Son ref={this.funSonRef}></Son>
        {/* 函数组件内部使用useRef */}
        <CustomTextInput></CustomTextInput>
        {/* 使用回调 refs */}
        {true && <CallBackRef></CallBackRef>}
        {/* 通过回调 refs  穿透绑定 */}
        {true && <Parent></Parent>}
      </div>
    )
  }
}

export class RefSon extends React.Component {
  constructor(props) {
    super(props)
    this.state = { isToggleOn: true }
    this.textInput = React.createRef()
    this.focusTextInput = this.focusTextInput.bind(this)
  }

  focusTextInput() {
    // 直接使用原生 API 使 text 输入框获得焦点
    // 注意：我们通过 "current" 来访问 DOM 节点
    console.log('son__focusTextInput...')
    this.textInput.current.focus()
  }
  render() {
    return (
      <div style={boxStyle}>
        <p>这是class子组件</p>
        {/* input设置value后需要 onchange去更新自己的内容 */}
        <input type="text" ref={this.textInput} />
        <input type="button" value="Focus the text input" onClick={this.focusTextInput} />
      </div>
    )
  }
}

function Son(props) {
  return (
    <div style={boxStyle}>
      <p>这是函数子组件</p>
    </div>
  )
}

// 你不能在函数组件上使用 ref 属性，因为他们没有实例。
// 你可以在函数组件内部使用 ref 属性，只要它指向一个 DOM 元素或 class 组件：
function CustomTextInput(props) {
  // 这里必须声明 textInput，这样 ref 才可以引用它
  const textInput = useRef(null)

  function handleClick() {
    textInput.current.focus()
  }

  return (
    <div style={boxStyle}>
      <p>函数组件内部使用useRef</p>
      <input type="text" ref={textInput} />
      <input type="button" value="Focus the text input" onClick={handleClick} />
    </div>
  )
}

// 不同于传递 createRef() 创建的 ref 属性，你会传递一个函数。
// 这个函数中接受 React 组件实例或 HTML DOM 元素作为参数，以使它们能在其他地方被存储和访问。
class CallBackRef extends React.Component {
  constructor(props) {
    super(props)
    this.textInput = null
    this.setTextInputRef = (element) => {
      this.textInput = element
    }
    this.focusTextInput = () => {
      // 使用原生 DOM API 使 text 输入框获得焦点
      if (this.textInput) this.textInput.focus()
    }
  }

  componentDidMount() {
    // 组件挂载后，让文本框自动获得焦点
    this.focusTextInput()
  }

  render() {
    // 使用 `ref` 的回调函数将 text 输入框 DOM 节点的引用存储到 React
    // 实例上（比如 this.textInput）
    return (
      <div style={boxStyle}>
        <p>通过回调 refs</p>
        <input type="text" ref={this.setTextInputRef} />
        <input type="button" value="Focus the text input" onClick={this.focusTextInput} />
      </div>
    )
  }
}

function SonLevel1(props) {
    console.log('SonLevel1...',props)
  return (
    <div style={boxStyle}>
      <p>这是一级子组件</p>
      <SonLevel2 {...props} />
    </div>
  )
}

function SonLevel2(props) {
    console.log('SonLevel2...',props)
  return (
    <div style={boxStyle}>
      <p>这是二级子组件</p>
      <input ref={props.inputRef} />
    </div>
  )
}

class Parent extends React.Component {
  componentDidMount() {
    console.log('Parent----InputRef...', this.inputElement)
  }
  render() {
    return (
      <div>
        <SonLevel1 inputRef={(el) => (this.inputElement = el)} />
      </div>
    )
  }
}
